<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>面向对象 - JavaScript</title>
</head>
<body>
    <h1>面向对象</h1>

    <h4>学习目标</h4>
    <ol>
        <li>需要逐步了解和应用面向对象的思想</li>
        <li>熟悉JavaScript中创建类和实例化的语法</li>
        <li>了解JavaScript的原型链</li>
    </ol>

    <script type="text/javascript">

        // --------------------------------------------------------------------
        // -- 面向对象
        // --------------------------------------------------------------------


        // --------------------------------------------------------------------
        // -- 面向对象
        // --------------------------------------------------------------------
        /*
            面向对象  (Object Oriented,OO) 的思想对软件开发相当重要，它的概念和应用甚至已超越了程序设计和软件开发，
            扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD 技术、人工智能等领域。
            面向对象是一种 对现实世界理解和抽象的方法，是计算机编程技术发展到一定阶段后的产物。
        */

        // ----------------------------------------------------
        // -- 语法
        // ----------------------------------------------------

        // -----------------------------
        // 1. 类（class）
        // -----------------------------
        /*
            在面向对象编程中，类（class）是对象（object）的模板，定义了同一组对象（又称”实例”）共有的属性和方法。

            在es5中，用function关键词声明。
            声明语法:
                function 类名([属性1, 属性2, ...]) {
                    代码块
                }
                注：属性可选，可以不传属性，也可以传入若干个属性
                注：类中可以 this 这个关键词表示当前对象
                注：类名首字母用大写

             new实例语法：
                new 类名([属性1, 属性2, ...]);
         */
        // 1.1 声明一个学生对象，有姓名、性别、生日字段

        // let student = {name: "王子晴", sex: "女", birth: "2001-05-06"};
        // console.log(student);
        // console.log(student.name);

        // 1.2 再次声明一个学生对象，有姓名、性别、生日字段，值和上面的不一样。

        // let student2 = {name: "夏雪若", sex: "女", birth: "2001-03-28"};
        // console.log(student2);
        // console.log(student2.birth);

        // 1.3 计算上面两个学生对象的年龄

        // student.getAge = function () {
        //     let date = new Date();
        //     let year = date.getFullYear();
        //     console.log("今年", year);
        //
        //     let birthDate = new Date("2001-05-06");
        //     let birthYear = birthDate.getFullYear();
        //     console.log("生日", birthYear);
        //
        //     return year - birthYear;
        // };
        //
        // console.log("学生", student.name, "年龄", student.getAge());
        //
        // student2.getAge = function () {
        //     let date = new Date();
        //     let year = date.getFullYear();
        //     console.log("今年", year);
        //
        //     let birthDate = new Date("2001-03-28");
        //     let birthYear = birthDate.getFullYear();
        //     console.log("生日", birthYear);
        //
        //     return year - birthYear;
        // };
        //
        // console.log("学生", student2.name, "年龄", student2.getAge());

        // 1.4 声明一个学生类，需要传入名称、性别、生日

        // function Student(name, sex, birth) {
        //     this.name = name;
        //     this.sex = sex;
        //     this.birth = birth;
        // }
        // let student = new Student("老子", "男", "2000-11-30");
        // console.log(student);

        // 1.5 在上面的类的基础上，增加获取名称、获取性别、获取年龄的方法

        // function Student(name, sex, birth) {
        //     this.name = name;
        //     this.sex = sex;
        //     this.birth = birth;
        //     this.getName = function () {
        //         return this.name;
        //     };
        //     this.getSex = function () {
        //         return this.sex;
        //     };
        //     this.getAge = function () {
        //         let date = new Date();
        //         let year = date.getFullYear();
        //         console.log("今年", year);
        //
        //         let birthDate = new Date(this.birth);
        //         let birthYear = birthDate.getFullYear();
        //         console.log("生日", birthYear);
        //
        //         return year - birthYear;
        //     }
        // }
        // let student = new Student("墨子", "男", "1999-01-02");
        // console.log("直接通过属性取得学生名称:", student.name);
        // console.log("通过方法取得的学生名称:", student.getName());
        // console.log("通过方法取得的学生年龄", student.getAge());
        //
        // let student2 = new Student("老夫子", "男", "2002-10-11");
        // console.log("student2学生的年龄", student2.getAge());

        // 1.6 方法(method)和函数(function)的区别？

        // 方法也是函数
        // 类的函数一般叫做方法(method)

        // 1.7 在上面类的基础上，增加设置名称，设置性别，设置生日的方法

        // function Student(name, sex, birth) {
        //     this.name = name;
        //     this.sex = sex;
        //     this.birth = birth;
        //     this.setName = function (name) {
        //         this.name = name;
        //     };
        //     this.getName = function () {
        //         return this.name;
        //     };
        //     this.setSex = function (sex) {
        //         this.sex = sex;
        //     };
        //     this.getSex = function () {
        //         return this.sex;
        //     };
        //     this.setBirth = function (birth) {
        //         this.birth = birth;
        //     };
        //     this.getBirth = function () {
        //         return this.birth;
        //     };
        //     this.getAge = function () {
        //         let date = new Date();
        //         let year = date.getFullYear();
        //         console.log("今年", year);
        //
        //         let birthDate = new Date(this.birth);
        //         let birthYear = birthDate.getFullYear();
        //         console.log("生日", birthYear);
        //
        //         return year - birthYear;
        //     }
        // }
        // let student = new Student();
        // student.setName("亚瑟");
        // student.setSex("男");
        // student.setBirth("2000-01-01");
        // console.log(student);
        // console.log(student.getName(), student.getSex(), student.getAge());

        // 1.8 对象、实例、类是什么？instanceof 运算符

        //对象是一种数据类型
        //实例 有具体的数值,实际的例子
        //类 一个模板
        // console.log(student instanceof Student); // true

        // 1.9 什么是属性和方法？
        // 1.10 this关键词表示什么？

        // let student2 = new Student("小乔");
        // console.log(sutdent2.getName()); //小乔

        // 1.11 构造方法是什么？
        // 1.12 通过set方法来设置，和构造方法直接传属性有什么不一样的？
        // 1.13 使用 instanceof 运算符判断学生对象是否是学生类的实例。


        // -----------------------------
        // 2. 继承（extends）
        // -----------------------------
        /*
            继承性是子类自动共享父类数据结构和方法的机制，这是类之间的一种关系。在定义和实现一个类的时候，可以在一个已经存在的类的基础之上来进行，把这个已经存在的类所定义的内容作为自己的内容，并加入若干新的内容。

            大部分语言继承都是用extends关键词，ES5中没有extends关键词，使用原型链的方式。

            在 JavaScript 中，每个对象都有一个指向它的原型（prototype）对象的内部链接。这个原型对象又有自己的原型，直到某个对象的原型为 null 为止（也就是不再有原型指向），组成这条链的最后一环。这种一级一级的链结构就称为原型链（prototype chain）。

            原型链实际上在定义一个对象的时候原型链本身就已经生成了，如果一个对象某个属性找不到，会沿着它的原型往上去寻找，直到原型链的最后才会停止寻找。

            语法:
                子类.prototype = new 父类();
         */
        // 2.1 声明计应班学生类，有姓名、性别、生日、php分数属性，有相关set和get方法，有获取年龄的方法

        function JYStudent(name, sex, birth, phpScore) {
            this.name = name;
            this.sex = sex;
            this.birth = birth;
            this.setName = function (name) {
                this.name = name;
            };
            this.getName = function () {
                return this.name;
            };
            this.setSex = function (sex) {
                this.sex = sex;
            };
            this.getSex = function () {
                return this.sex;
            };
            this.setBirth = function (birth) {
                this.birth = birth;
            };
            this.getBirht = function () {
                return this.birth;
            };
            this.setPhpScore = function (phpScore) {
                this.phpScore = phpScore;
            };
            this.getPhpScore = function () {
                return phpScore;
            };
            this.getAge = function () {
                let date = new Date();
                let year = date.getFullYear();
                console.log("今年", year);

                let birthDate = new Date(this.birth);
                let birthYear = birthDate.getFullYear();
                console.log("生日", birthYear);

                return year - birthYear;
            }
        }
        // let student = new JY_Student("林河森", "男", "2000-11-30", "88");
        // console.log(student.getName(), student.getSex(), student.getAge(), student.getPhpScore());

        // 2.2 声明软件班学生类，有姓名、性别、生日、asp.net分数属性，有相关set和get方法，有获取年龄的方法

        // function rjStudent(name, sex, birth, aspNetScore) {
        //     this.name = name;
        //     this.sex = sex;
        //     this.birth = birth;
        //     this.aspNetScore = aspNetScore;
        //     this.setName = function (name) {
        //         this.name = name;
        //     };
        //     this.getName = function () {
        //         return this.name;
        //     };
        //     this.setSex = function (sex) {
        //         this.sex = sex;
        //     };
        //     this.getSex = function () {
        //         return this.sex;
        //     };
        //     this.setBirth = function (birth) {
        //         this.birth = birth;
        //     };
        //     this.getBirth = function () {
        //         return this.birth;
        //     };
        //     this.setAspNetScore = function (aspNetScore) {
        //         this.aspNetScore = aspNetScore;
        //     };
        //     this.getAspNetScore = function () {
        //         return this.aspNetScore;
        //     };
        //     this.getAge = function () {
        //         let date = new Date();
        //         let year = date.getFullYear();
        //         console.log("今年", year);
        //
        //         let birthDate = new Date(this.birth);
        //         let birthYear = birthDate.getFullYear();
        //         console.log("生日", birthYear);
        //
        //         return year - birthYear;
        //     }
        // }
        // let student = new RJ_Student("梁艺缤", "男", "2001-01-01", "77");
        // console.log(student.getName(), student.getSex(), student.getAge(), student.getAspNetScore());

        // 2.3 观察一下上面的两个类是不是和学生类的东西大量重复了？

        //------------------
        //--创建基类（父类）--
        //------------------
        // function Student(name, sex, birth) {
        //     this.name = name;
        //     this.sex = sex;
        //     this.birth = birth;
        //     this.setName = function (name) {
        //         this.name = name;
        //     };
        //     this.getName = function () {
        //         return this.name;
        //     };
        //     this.setSex = function (sex) {
        //         this.sex = sex;
        //     };
        //     this.getSex = function () {
        //         return this.sex;
        //     };
        //     this.setBirth = function (birth) {
        //         this.birth = birth;
        //     };
        //     this.getBirth = function () {
        //         return this.birth;
        //     };
        //     this.getAge = function () {
        //         let date = new Date();
        //         let year = date.getFullYear();
        //         console.log("今年", year);
        //
        //         let birthDate = new Date(this.birth);
        //         let birthYear = birthDate.getFullYear();
        //         console.log("生日", birthYear);
        //
        //         return year - birthYear;
        //     }
        // }

        // 2.4 改写计应班学生类，继承上例学生类

        // function JYStudent(phpScore) {
        //     this.phpScore = phpScore;
        //     this.setPhpScore = function (phpScore) {
        //         this.phpScore = phpScore;
        //     };
        //     this.getPhpScore = function () {
        //         return this.phpScore;
        //     };
        // }
        // JYStudent.prototype = new Student();
        //
        // let jyStudent = new JYStudent(80);
        // jyStudent.setName("万磁王");
        // console.log(jyStudent);
        // console.log(jyStudent.getName());
        // console.log(jyStudent.getBirth());
        // console.log(jyStudent.toString());

        // 2.5 改写软件班学生类，继承上例学生类

        // function RJStudent(aspNetScore) {
        //     this.aspNetScore = aspNetScore;
        //     this.setAspNetScore = function (aspNetScore) {
        //         this.aspNetScore = aspNetScore;
        //     };
        //     this.getAspNetScore = function () {
        //         return this.aspNetScore;
        //     }
        // }
        // RJStudent.prototype = new Student();
        // let rjStudent = new RJStudent(85);
        // rjStudent.setName("梁艺缤");
        // console.log(rjStudent);

        // 2.6 查看计应班学生类、软件班学生类原型链
        // 2.7 使用 instanceof 运算符 查看计应班和软件班的学生实例是否是学生类的实例？

        // console.log(jyStudent instanceof JYStudent); // true
        // console.log(jyStudent instanceof Student); // ture
        // console.log(rjStudent instanceof RJStudent); // true
        // console.log(rjStudent instanceof Student); // ture
        // //课程类
        // function Course() {
        //
        // }
        // console.log(jyStudent instanceof Course); // false

        // 2.8 分别声明数字对象、字符串对象、布尔对象、数组、对象，查看其原型链

        //数字对象
        // let num = 10;
        // console.log(num);
        // console.log(num.toFixed(2));
        // console.log(num.toString());
        // let numObj = new Number(1);
        // console.log(numObj);

        //字符串对象
        // let str = "1";
        // console.log(str);
        // console.log(str.padStart(2, "0"));
        //
        // let str2 = "hello world";
        // console.log(str2.indexOf("l")); // 2
        // console.log(str2.indexOf("e")); // 1
        // console.log(str2.indexOf("h")); // 0
        // console.log(str2.indexOf("o")); // 4
        //
        // let strObj = new String("1");
        // console.log(strObj);

        //布尔对象
        // let boolean = true;
        // console.log(boolean.toString());
        // console.log(boolean.valueOf());

        // new Boolean(true);	//构造函数
        // Boolean(false);		//转换函数
        // console.log(Boolean.toString());
        // console.log(Boolean.valueOf());

        //数组
        // let arr = ["车", "房", "四件套", "五金", "彩礼"];
        // console.log(arr);
        // console.log(arr.length);

        // -----------------------------
        // 3. 多态（Polymorphism）
        // -----------------------------
        /*
            多态（Polymorphism）按字面的意思就是“多种状态”。在面向对象语言中，接口的多种不同的实现方式即为多态。

            实现多态通常会重写（override）父类的方法。
         */
        // 3.1. 参考上面学生的类Student，定义学习的方法，输出：学习软件编程技术

        // function Student(name, sex, birth) {
        //     this.name = name;
        //     this.sex = sex;
        //     this.birth = birth;
        //     this.setName = function (name) {
        //         this.name = name;
        //     };
        //     this.getName = function () {
        //         return this.name;
        //     };
        //     this.setSex = function (sex) {
        //         this.sex = sex;
        //     };
        //     this.getSex = function () {
        //         return this.sex;
        //     };
        //     this.setBirth = function (birth) {
        //         this.birth = birth;
        //     };
        //     this.getBirth = function () {
        //         return this.birth;
        //     };
        //     this.getAge = function () {
        //         let date = new Date();
        //         let year = date.getFullYear();
        //         console.log("今年", year);
        //
        //         let birthDate = new Date(this.birth);
        //         let birthYear = birthDate.getFullYear();
        //         console.log("生日", birthYear);
        //
        //         return year - birthYear;
        //     };
        //     this.learn = function () {
        //         console.log("学习软件编程技术");
        //     }
        // }
        // let student = new Student("十六夜");
        // student.learn();
        
        // 3.2. 计应班的同学学习是LNMP，在计应班学生类重写学习方法，输出：学习LNMP
        // LNMP Linux Nginx MySql PHP

        // function JYStudent(phpScore) {
        //     this.phpScore = phpScore;
        //     this.setPhpScore = function () {
        //         this.phpScore = phpScore;
        //     };
        //     this.getPhpScore = function () {
        //         return phpScore;
        //     };
        //     this.learn = function () {
        //         console.log(this.name + " : " + "学习LNMP");
        //     }
        // }
        // JYStudent.prototype = new Student();
        //
        // let jyStudent = new JYStudent();
        // jyStudent.setName("计应班同学");
        // jyStudent.learn();
        // console.log(jyStudent);

        // 3.3. 软件班的同学学习是asp.net，在软件班学生类重写学习方法，输出：学习asp.net

        // function RJStudent(aspNetScore) {
        //     this.aspNetScore = aspNetScore;
        //     this.setAspNetScore = function (aspNetScore) {
        //         this.aspNetScore = aspNetScore;
        //     };
        //     this.getAspNetScore = function () {
        //         return this.aspNetScore;
        //     };
        //     this.learn = function () {
        //         console.log(this.name + " : " + "学习asp.net");
        //     }
        // }
        // RJStudent.prototype = new Student();
        //
        // let rjStudent = new RJStudent();
        // rjStudent.setName("软件班同学");
        // rjStudent.learn();
        // console.log(rjStudent);

        // 3.4. 方法和函数的区别？

        // 方法method 函数functioon
        // 方法也是函数
        // 类的函数一般叫做方法(method)

        // -----------------------------
        // 4. 重载（overload）
        // -----------------------------
        /*
            js没有严格意义的重载
            函数名(方法名)相同,参数不同(类型不同、数量不同)
         */


        // -----------------------------
        // 5. 接口（interface）
        // -----------------------------
        /*
            js没有严格意义的接口

         */


        // -----------------------------
        // 6. es6中的语法
        // -----------------------------
        /*
            es6中增加了class的语法糖，本质是根据上面实现的。
            语法：
                class 类名 {
                    constructor(属性1, 属性2, ...) {
                        构造方法体
                    }

                    方法1名(参数1, 参数2, ...) {
                        方法体
                    }
                    方法2名(参数1, 参数2, ...) {
                        方法体
                    }
                    ...
                }
                注：类里声明方法，不用加function
                注：类里可以声明多个方法
         */
        // 6.1 使用新语法糖实现上面的学生类、计应班学生类、软件班学生类

        // class Studnet {
        //     constructor(name, sex, birth){
        //         this.name = name;
        //         this.sex = sex;
        //         this.birth = birth;
        //     }
        //     setName(name){
        //         this.name = name;
        //     }
        //     getName(){
        //         return this.name;
        //     }
        // }
        // let student = new Studnet("张三");
        // console.log(student);

        // 6.2 新语法糖和旧的用哪个？

        // 1.真正将需求转化成了代码
        // 2.写出可读的，容易维护的，方便理解的代码
        // 具情况论,特别适合OOP的就用Class。
        // O(Object对象)O(Oriented面向对象)P(Programming编程)面向对象编程
        /* OOP 只是一套帮助开发者设计和编写软件的方法论，
        * 但并不代表它能解决所有领域的问题，
        * 也不是能在所有编程语言的任何场景下都适用。
        * 我们应避免陷入这种教条主义。
        */

        // -----------------------------
        // 7. 面向对象思想在数据库表结构设计的应用
        // -----------------------------
        // 7.1 回顾一下数据库课程的学生管理系统的表设计, 思考和类、对象是否有一点相通的感觉?

        // function Class() {
        //     this.name = null;
        // }
        // function ClassCourse() {
        //
        // }
        // function Course() {
        //
        // }
        // function Score() {
        //
        // }
        // function Student() {
        //
        // }

        // ----------------------------------------------------
        // -- 练习
        // ----------------------------------------------------
        // 1. 声明一个动物类，有名称属性，有睡觉方法。

        // function Animal(name) {
        //     this.name = name;
        //     this.sleep = function () {
        //         console.log("睡觉");
        //     }
        // }

        // 2. 声明一个斑马类，继承动物类，重写睡觉方法。

        // function Zebra() {
        //     this.sleep = function () {
        //         console.log("斑马站着睡觉");
        //     }
        // }
        // Zebra.prototype = new Animal();
        // let zebra = new Zebra();
        // zebra.sleep();

        // 3. 声明一个鱼类，继承动物类，重写睡觉方法。

        // function Fish() {
        //     this.sleep = function () {
        //         console.log("睁着眼睛睡觉");
        //     }
        // }
        // Fish.prototype = new Animal();
        // let fish = new Fish();
        // fish.sleep();

        // 4. 声明一个鸟类，继承动物类，重写睡觉方法。

        // function Bird() {
        //     this.sleep = function () {
        //         console.log("鸟的睡姿各种各样");
        //     }
        // }
        // Bird.prototype = new Animal();
        // let bird = new Bird();
        // bird.sleep();

        // 5. 声明一个人类，继承动物类，重写睡觉方法。

        // function Human() {
        //     this.sleep = function () {
        //         console.log("躺着睡,需要舒服的床");
        //     }
        // }
        // Human.prototype = new Animal();
        // let human = new Human();
        // human.sleep();

        // 6. 参考网页新闻内容页, 需要设计哪些对象?
        /*
         * 通过面向对象的思想,分析业务相关对象,设计成表结构。
         * 新闻对象:
         *      新闻标题
         *      新闻内容
         *      新闻发布时间
         *      新闻来源
         *      新闻原标题
         *      新闻跟帖人数
         *      新闻举报
         *      责任编辑
         *
         * 专题对象:
         *      专题推荐
         *      专题标题
         *      专题图片
         *
         * 转发对象:
         *      分享(转发)渠道(途径)
         *      转发渠道名称
         *      转发渠道图标
         */




    </script>
</body>
</html>